﻿using AiMoWindows.CodeScripts.IO;
using AiMoWindows.Localization;
using AiMoWindows.MainActions.LibraryActions;
using System.Text;

namespace AiMoWindows.Compiler
{
    class RhpCompileSource : ICompilerScript
    {
        CompileCodeUnit[] CompileUnits { get; }
        public string AuthorInfo { get; set; }
        public RhpCompileSource(ScriptsLibraryItem[] sources, string authorInfo)
        {
            AuthorInfo = authorInfo;
            List<CompileCodeUnit> compileCodes = new List<CompileCodeUnit>();
            foreach (ScriptsLibraryItem item in sources)
            {
                string compileContent = CreateRhpCompileCode(item);
                compileCodes.Add(new CompileCodeUnit(compileContent, item.Name + CodeIO.Extension));
            }
            CompileUnits = compileCodes.ToArray();
        }

        readonly string compileBaseString =
@"
[HereIsUsingCode]6939FC2E
namespace RhpCompile
{
    public class Command[CommandClassName]8859F6F6 : RhpBaseScripts
    {
        public override string EnglishName => [EnglishName]887D40B6;
        protected override string RunCommandInfo => [UserCommandInfo]89F6F0B6;
	    protected override void Run()
	    {
[HereIsRunCode]887D40B6
	    }
[HereIsFuncCode]B59F6F62
    }
[HereIsOtherClassCode]9DDD6BC2
}
";
        string CreateRhpCompileCode(ScriptsLibraryItem item)
        {
            string authorInfo = "";
            if (!string.IsNullOrEmpty(AuthorInfo)) authorInfo += string.Format(Local.Get("Current command {0} is written by {1}"), item.CommandEnglishName, AuthorInfo) + "\\r\\n";
            authorInfo += Local.Get("Scripts powered and exported by AiMo3D (https://aimo.zhai-zhai.com)");
            return compileBaseString
                .Replace("[HereIsUsingCode]6939FC2E", item.Script.GetUsingsCode())
                .Replace("[CommandClassName]8859F6F6", item.CommandEnglishName)
                .Replace("[UserCommandInfo]89F6F0B6", "\"" + authorInfo + "\"")
                .Replace("[EnglishName]887D40B6", "\"" + item.CommandEnglishName + "\"")
                .Replace("[HereIsRunCode]887D40B6", item.Script.MainCode.ToString())
                .Replace("[HereIsFuncCode]B59F6F62", item.Script.AdditionalFunctionCode.ToString())
                .Replace("[HereIsOtherClassCode]9DDD6BC2", item.Script.AdditionalClassCode.ToString())
                ;
        }
        /// <summary>
        /// 如果更新了AimoRhino的代码，需要同步更新编译成RHP的代码
        /// </summary>
        List<CompileCodeUnit> DefaultCompileContexts()
        {
            return new List<CompileCodeUnit>
            {
                new CompileCodeUnit(forCompile_BaseScript,"Default_BaseScript.cs"),
                new CompileCodeUnit(forCompile_Previewer,"Default_Previewer.cs"),
                new CompileCodeUnit(forCompile_AimoStaticUtils,"Default_AimoStaticUtils.cs"),
                new CompileCodeUnit(pluginClass,"Default_Plugin.cs"),
                new CompileCodeUnit(pluginAssemblyInfo.Replace("[PluginGuid]FDDD6BCF",Guid.NewGuid().ToString()),"Default_AssemblyInfo.cs"),
            };
        }
        void ICompilerScript.OnCompileSuccess(CompiledResult result)
        {

        }
        public string GetScriptHash()
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach (CompileCodeUnit unit in CompileUnits)
            {
                stringBuilder.Append(unit.Content);
            }
            return Utils.CalculateStringMD5(stringBuilder.ToString());
        }
        public string GetReferenceExistedChangedHash() => "";

        string[] ICompilerScript.GetReferenceAssemblies() => Array.Empty<string>();
        public CompileCodeUnit[] GetCodeForCompiler()
        {
            var list = DefaultCompileContexts();
            list.AddRange(CompileUnits);
            return list.ToArray();
        }

        readonly string pluginClass =
@"using Rhino.PlugIns;
namespace RhpCompile
{
    public class AiMoExportPlugin : Rhino.PlugIns.PlugIn
    {
        public AiMoExportPlugin()
        {
            Instance = this;
        }
        public static AiMoExportPlugin Instance { get; private set; }
    }
}
";

        readonly string pluginAssemblyInfo =
@"
using Rhino.PlugIns;
using System.Runtime.InteropServices;
[assembly: PlugInDescription(DescriptionType.Address, ""AiMo3D@zhai-zhai.cn"")]
[assembly: PlugInDescription(DescriptionType.Country, ""China"")]
[assembly: PlugInDescription(DescriptionType.Email, """")]
[assembly: PlugInDescription(DescriptionType.Phone, """")]
[assembly: PlugInDescription(DescriptionType.Fax, """")]
[assembly: PlugInDescription(DescriptionType.Organization, """")]
[assembly: PlugInDescription(DescriptionType.UpdateUrl, """")]
[assembly: PlugInDescription(DescriptionType.WebSite, """")]
[assembly: PlugInDescription(DescriptionType.Icon, """")]
[assembly: Guid(""[PluginGuid]FDDD6BCF"")]
";

        readonly string forCompile_BaseScript =
@"using Rhino;
using Rhino.Commands;
using Rhino.Display;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.Input.Custom;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Threading;
namespace RhpCompile
{
    public abstract class RhpBaseScripts : Command
    {
        readonly Previewer previewer;
        public RhpBaseScripts()
        {
            previewer = Previewer.Instance;
            try
            {
                OnLoad();
            }
            catch (Exception ex)
            {
                RhinoApp.WriteLine(""警告：载入时OnLoad()代码运行出错：\n"" + ex.ToString());
            }
        }
        public void Dispose()
        {
            LoopOff();
            previewer.ClosePreview();
        }
        public virtual void OnLoad()
        {
        }
        protected abstract void Run();
        protected virtual string RunCommandInfo => """";
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            try
            {
                LoopOff();
                previewer.Clear();
                previewer.EnableDraw();
                Run();
                if (previewer.IsEmpty && (!OnLoop))
                {
                    previewer.ClosePreview();
                }
                RhinoDoc.ActiveDoc.Views.Redraw();
                if (!string.IsNullOrEmpty(RunCommandInfo))
                {
                    Print(RunCommandInfo);
                }
                return Result.Success;
            }
            catch (Exception ex)
            {
                RhinoApp.WriteLine($""{EnglishName} Command Error: "");
                RhinoApp.WriteLine(ex.Message);
                RhinoApp.WriteLine(ex.StackTrace);
            }
            return Result.Failure;
        }
        #region Show
        public void Show(object geometry, Color color)
        {
            previewer.Preview(geometry, color);
        }
        public void Show(object geometry)
        {
            previewer.Preview(geometry, Previewer.DefaultColor);
        }
        /// <summary>
        /// 重绘所有Rhino视图
        /// </summary>
        public void RedrawAll()
        {
            RhinoDoc.ActiveDoc.Views.Redraw();
        }
        public void Redraw()
        {
            RhinoDoc.ActiveDoc.Views.ActiveView.Redraw();
        }
        public void ClearShow()
        {
            previewer.Clear();
        }
        public void Show<T>(IEnumerable<T> geometries)
        {
            if (geometries is Polyline polyline)
            {
                previewer.Preview(polyline, Previewer.DefaultColor);
                return;
            }
            foreach (T geo in geometries)
                previewer.Preview(geo, Previewer.DefaultColor);
        }

        public void Show<T>(IEnumerable<T> geometries, Color color)
        {
            if (geometries is Polyline polyline)
            {
                previewer.Preview(polyline, color);
                return;
            }
            foreach (T geo in geometries)
                previewer.Preview(geo, color);
        }
        public void Show(Vector3d vector3d, Point3d from, Color color)
        {
            previewer.Preview(vector3d, from, color);
        }
        public void Show(Vector3d vector3d, Point3d from)
        {
            previewer.Preview(vector3d, from, Previewer.DefaultColor);
        }

        public void Show(string text, Point3d location, int height = 12)
        {
            Show(text, location, height, Previewer.DefaultColor);
        }
        public void Show(string text, Point3d location, int height, Color color)
        {
            TextDot textDot = new TextDot(text, location)
            {
                FontHeight = height,
            };
            Show(textDot, color);
        }
        public void Show(string text, Plane plane, double height)
        {
            Color color = Color.FromArgb(255, Previewer.DefaultColor);

            Show(text, plane, height, color);
        }
        public void Show(string text, Plane plane, double height, Color color)
        {
            Text3d text3D = new Text3d(text, plane, height)
            {
                HorizontalAlignment = TextHorizontalAlignment.Center,
                VerticalAlignment = TextVerticalAlignment.Middle,
            };
            Show(text3D, color);
        }
        #endregion
        #region Select
        class GetCircleObject : GetObject
        {
            public override bool CustomGeometryFilter(RhinoObject rhObject, GeometryBase geometry, ComponentIndex componentIndex)
            {
                return geometry.ObjectType == ObjectType.Curve && geometry is Curve crv && crv.TryGetCircle(out _);
            }
        }
        class GetLineObject : GetObject
        {
            public override bool CustomGeometryFilter(RhinoObject rhObject, GeometryBase geometry, ComponentIndex componentIndex)
            {
                return geometry.ObjectType == ObjectType.Curve && geometry is Curve crv && crv.IsLinear();
            }
        }
        class GetPolylineObject : GetObject
        {
            public override bool CustomGeometryFilter(RhinoObject rhObject, GeometryBase geometry, ComponentIndex componentIndex)
            {
                return geometry.ObjectType == ObjectType.Curve && geometry is Curve crv && crv.TryGetPolyline(out _);
            }
        }
        class GetTextEntityObject : GetObject
        {
            public override bool CustomGeometryFilter(RhinoObject rhObject, GeometryBase geometry, ComponentIndex componentIndex)
            {
                return geometry.ObjectType == ObjectType.Annotation && geometry is TextEntity text && text.IsValid;
            }
        }
        void ClearSelect()
        {
            RhinoDoc.ActiveDoc.Objects.UnselectAll();
        }
        public bool Select(out RhinoObject[] rhinoObjects) => Select(out rhinoObjects, ObjectType.AnyObject, """");
        public bool Select(out RhinoObject[] rhinoObjects, ObjectType objectType) => Select(out rhinoObjects, objectType, """");
        /// <summary>
        /// 选取多个Rhino物体，可以指定选择的ObjectType。
        /// 成功返回True。
        /// </summary>
        public bool Select(out RhinoObject[] rhinoObjects, ObjectType objectType, string prompts)
        {
            GetObject get = new GetObject();
            if (string.IsNullOrEmpty(prompts)) prompts = $""请选择多个物体：{objectType}"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.GeometryFilter = objectType;
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
                rhinoObjects = get.Objects().Select(x => x.Object()).ToArray();
            else
                rhinoObjects = null;
            ClearSelect();
            return re;
        }
        public bool Select(out RhinoObject rhinoObject) => Select(out rhinoObject, ObjectType.AnyObject, """");
        public bool Select(out RhinoObject rhinoObject, ObjectType objectType) => Select(out rhinoObject, objectType, """");
        /// <summary>
        /// 选取一个Rhino物体，可以指定选择的ObjectType。
        /// 成功返回True。
        /// </summary>
        public bool Select(out RhinoObject rhinoObject, ObjectType objectType, string prompts)
        {
            GetObject get = new GetObject();
            if (string.IsNullOrEmpty(prompts)) prompts = $""请选择一个物体：{objectType}"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.GeometryFilter = objectType;
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
                rhinoObject = get.Object(0).Object();
            else
                rhinoObject = null;
            ClearSelect();
            return re;
        }
        public bool Select(out Polyline polyline) => Select(out polyline, """");
        /// <summary>
        /// 选取一个多段线，如果成功返回True
        /// </summary>
        public bool Select(out Polyline polyline, string prompts)
        {
            GetPolylineObject get = new GetPolylineObject();
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择一个多段线"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;

            if (re)
            {
                Curve curve = get.Object(0).Object().Geometry as Curve;
                if (curve.TryGetPolyline(out polyline)) return true;
            }
            polyline = null;
            ClearSelect();
            return false;
        }
        public bool Select(out Polyline[] polylines) => Select(out polylines, """");
        /// <summary>
        /// 选取多个多段线，如果成功返回True
        /// </summary>
        public bool Select(out Polyline[] polylines, string prompts)
        {
            GetPolylineObject get = new GetPolylineObject();
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择多个多段线"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            List<Polyline> list = new List<Polyline>();
            if (re)
            {
                foreach (var obj in get.Objects())
                {
                    if (obj.Object().Geometry is Curve crv && crv.TryGetPolyline(out Polyline pl))
                    {
                        list.Add(pl);
                    }
                }
            }
            polylines = list.ToArray();
            ClearSelect();
            return list.Count > 0;
        }

        public bool Select(out Circle[] circles) => Select(out circles, """");
        public bool Select(out Circle[] circles, string prompts)
        {
            GetCircleObject get = new GetCircleObject();
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择多个圆"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            List<Circle> list = new List<Circle>();
            if (re)
            {
                foreach (var obj in get.Objects())
                {
                    if (obj.Object().Geometry is Curve crv && crv.TryGetCircle(out Circle cir))
                    {
                        list.Add(cir);
                    }
                }
            }
            circles = list.ToArray();
            ClearSelect();
            return list.Count > 0;
        }
        public bool Select(out Circle circle) => Select(out circle, """");
        public bool Select(out Circle circle, string prompts)
        {
            GetCircleObject get = new GetCircleObject();
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择一个圆"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
            {
                Curve curve = get.Object(0).Object().Geometry as Curve;
                if (curve.TryGetCircle(out circle)) return true;
            }
            circle = Circle.Unset;
            ClearSelect();
            return false;
        }
        public bool Select(out Line[] lines) => Select(out lines, """");
        public bool Select(out Line[] lines, string prompts)
        {
            GetLineObject get = new GetLineObject();
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择多个线段"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            List<Line> list = new List<Line>();
            if (re)
            {
                foreach (var obj in get.Objects())
                {
                    if (obj.Object().Geometry is Curve crv)
                    {
                        list.Add(new Line(crv.PointAtStart, crv.PointAtEnd));
                    }
                }
            }
            lines = list.ToArray();
            ClearSelect();
            return list.Count > 0;
        }
        public bool Select(out Line line) => Select(out line, """");
        public bool Select(out Line line, string prompts)
        {
            GetLineObject get = new GetLineObject();
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择一个线段"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
            {
                Curve crv = get.Object(0).Object().Geometry as Curve;
                line = new Line(crv.PointAtStart, crv.PointAtEnd);

            }
            else line = Line.Unset;
            ClearSelect();
            return re;
        }
        public bool Select(out Curve[] curves) => Select(out curves, """");
        /// <summary>
        /// 选取多个曲线，如果成功返回True
        /// </summary>
        public bool Select(out Curve[] curve, string prompts)
        {
            curve = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Curve, prompts);
            if (re)
            {
                curve = objs.Select(x => x.Geometry as Curve).ToArray();
            }
            return re;
        }
        public bool Select(out Curve curve) => Select(out curve, """");
        /// <summary>
        /// 选取一个曲线，如果成功返回True
        /// </summary>
        public bool Select(out Curve curve, string prompts)
        {
            curve = null;
            bool re = Select(out RhinoObject obj, ObjectType.Curve, prompts);
            if (re)
            {
                curve = obj.Geometry as Curve;
            }
            return re;
        }
        public bool Select(out Mesh[] meshes) => Select(out meshes, """");
        /// <summary>
        /// 选取多个网格，如果成功返回True
        /// </summary>
        public bool Select(out Mesh[] meshes, string prompts)
        {
            meshes = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Mesh, prompts);
            if (re)
            {
                meshes = objs.Select(x => x.Geometry as Mesh).ToArray();
            }
            return re;
        }
        public bool Select(out Mesh mesh) => Select(out mesh, """");
        /// <summary>
        /// 选取一个网格，如果成功返回True
        /// </summary>
        public bool Select(out Mesh mesh, string prompts)
        {
            mesh = null;
            bool re = Select(out RhinoObject obj, ObjectType.Mesh, prompts);
            if (re)
            {
                mesh = obj.Geometry as Mesh;
            }
            return re;
        }
        public bool Select(out Brep[] breps) => Select(out breps, """");
        /// <summary>
        /// 选取多个多重曲面，如果成功返回True
        /// </summary>
        public bool Select(out Brep[] breps, string prompts)
        {
            breps = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Brep, prompts);
            if (re)
            {
                breps = objs.Select(x => ToBrep(x.Geometry)).ToArray();
            }
            return re && breps.All(x => x is Brep);
        }
        public bool Select(out Brep brep) => Select(out brep, """");
        /// <summary>
        /// 选取一个多重曲面，如果成功返回True
        /// </summary>
        public bool Select(out Brep brep, string prompts)
        {
            brep = null;
            bool re = Select(out RhinoObject obj, ObjectType.Brep, prompts);
            if (re)
            {
                brep = ToBrep(obj.Geometry);
            }
            return re && brep != null;
        }
        Brep ToBrep(GeometryBase geo)
        {
            Brep bp = geo as Brep;
            if (bp == null)
            {
                if (geo is Extrusion extrusion)
                {
                    bp = extrusion.ToBrep();
                }
            }
            return bp;
        }
        public bool Select(out Extrusion[] extrusions) => Select(out extrusions, """");
        /// <summary>
        /// 选取多个挤出物件，如果成功返回True
        /// </summary>
        public bool Select(out Extrusion[] extrusions, string prompts)
        {
            extrusions = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Extrusion, prompts);
            if (re)
            {
                extrusions = objs.Select(x => x.Geometry as Extrusion).ToArray();
            }
            return re;
        }
        public bool Select(out Extrusion extrusion) => Select(out extrusion, """");
        /// <summary>
        /// 选取一个挤出物件，如果成功返回True
        /// </summary>
        public bool Select(out Extrusion extrusion, string prompts)
        {
            extrusion = null;
            bool re = Select(out RhinoObject obj, ObjectType.Extrusion, prompts);
            if (re)
            {
                extrusion = obj.Geometry as Extrusion;
            }
            return re;
        }
        public bool Select(out Surface[] surfaces) => Select(out surfaces, """");
        /// <summary>
        /// 选取多个曲面，如果成功返回True
        /// </summary>
        public bool Select(out Surface[] surfaces, string prompts)
        {
            surfaces = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Surface, prompts);
            if (re)
            {
                surfaces = objs.Select(x => x.Geometry as Surface).ToArray();
            }
            return re;
        }
        public bool Select(out Surface surface) => Select(out surface, """");
        /// <summary>
        /// 选取一个曲面，如果成功返回True
        /// </summary>
        public bool Select(out Surface surface, string prompts)
        {
            surface = null;
            bool re = Select(out RhinoObject obj, ObjectType.Surface, prompts);
            if (re)
            {
                surface = obj.Geometry as Surface;
            }
            return re;
        }
        public bool Select(out InstanceObject[] instanceObjects) => Select(out instanceObjects, """");
        /// <summary>
        /// 选取多个图块物体，如果成功返回True
        /// </summary>
        public bool Select(out InstanceObject[] instanceObjects, string prompts)
        {
            instanceObjects = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.InstanceReference, prompts);
            if (re)
            {
                instanceObjects = objs.Cast<InstanceObject>().ToArray();
            }
            return re;
        }
        public bool Select(out InstanceObject instanceObject) => Select(out instanceObject, """");
        /// <summary>
        /// 选取一个图块物体，如果成功返回True
        /// </summary>
        public bool Select(out InstanceObject instanceObject, string prompts)
        {
            instanceObject = null;
            bool re = Select(out RhinoObject obj, ObjectType.InstanceReference, prompts);
            if (re)
            {
                instanceObject = obj as InstanceObject;
            }
            return re;
        }
        public bool Select(out TextEntity text) => Select(out text, """");
        public bool Select(out TextEntity text, string prompts)
        {
            GetTextEntityObject get = new GetTextEntityObject();
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择一个文字"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
            {
                text = get.Object(0).Object().Geometry as TextEntity;
            }
            else text = null;
            ClearSelect();
            return re;
        }
        public bool Select(out TextEntity[] texts) => Select(out texts, """");
        public bool Select(out TextEntity[] texts, string prompts)
        {
            GetTextEntityObject get = new GetTextEntityObject();
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择多个文字"";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            List<TextEntity> list = new List<TextEntity>();
            if (re)
            {
                foreach (var obj in get.Objects())
                {
                    if (obj.Object().Geometry is TextEntity text)
                    {
                        list.Add(text);
                    }
                }
            }
            texts = list.ToArray();
            ClearSelect();
            return list.Count > 0;
        }
        public bool Select(out Point3d pt) => Select(out pt, """");
        public bool Select(out Point3d pt, string prompts)
        {
            pt = Point3d.Unset;
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择点"";
            bool re = Select(out RhinoObject obj, ObjectType.Point, prompts);
            if (re)
            {
                Rhino.Geometry.Point ptGeo = obj.Geometry as Rhino.Geometry.Point;
                if (ptGeo != null)
                    pt = ptGeo.Location;
            }
            return pt.IsValid;
        }
        public bool Select(out Point3d[] pts) => Select(out pts, """");
        public bool Select(out Point3d[] pts, string prompts)
        {
            pts = null;
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择多个点"";
            bool re = Select(out RhinoObject[] objs, ObjectType.Point, prompts);
            if (re)
            {
                pts = objs.Select(x => x.Geometry).Cast<Rhino.Geometry.Point>().Select(x => x.Location).ToArray();
            }
            return re;
        }
        public bool Select(out GeometryBase geo) => Select(out geo, """");
        public bool Select(out GeometryBase geo, string prompts)
        {
            geo = null;
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择GeometryBase"";
            bool re = Select(out RhinoObject rhinoObject, ObjectType.AnyObject, prompts);
            if (re)
            {
                geo = rhinoObject.Geometry;
            }
            return geo != null;
        }
        public bool Select(out GeometryBase[] geos) => Select(out geos, """");
        public bool Select(out GeometryBase[] geos, string prompts)
        {
            geos = null;
            if (string.IsNullOrEmpty(prompts)) prompts = ""请选择多个GeometryBase"";
            bool re = Select(out RhinoObject[] rhinoObjects, ObjectType.AnyObject, prompts);
            if (re)
            {
                geos = rhinoObjects.Select(x => x.Geometry).ToArray();
            }
            return re;
        }
        #endregion
        #region Bake
        public Guid Bake(Point3d geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid Bake(Point3f geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid Bake(PointCloud geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Point3d> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Point3d> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Point3f> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Point3f> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<PointCloud> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<PointCloud> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(Line geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Line> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Line> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(Box geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Box> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Box> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }

        public Guid Bake(BoundingBox geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<BoundingBox> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<BoundingBox> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }

        public Guid Bake(Circle geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Circle> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Circle> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }

        public Guid Bake(Arc geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Arc> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Arc> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(Ellipse geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Ellipse> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Ellipse> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }

        public Guid Bake(Cone geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Cone> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Cone> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(Rectangle3d geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Rectangle3d> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Rectangle3d> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(Polyline geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Polyline> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Polyline> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(Cylinder geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Cylinder> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Cylinder> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(Plane geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Plane> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Plane> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(Sphere geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Sphere> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Sphere> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(GeometryBase geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<GeometryBase> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<GeometryBase> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }

        public Guid Bake(RhinoObject geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<RhinoObject> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<RhinoObject> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid Bake(string text, Point3d location, int height = 12, ObjectAttributes objectAttributes = null)
        {
            TextDot textDot = new TextDot(text, location)
            {
                FontHeight = height,
            };
            return BakeOne(textDot, objectAttributes);
        }
        public Guid Bake(string text, Plane plane, double height = 12, ObjectAttributes objectAttributes = null)
        {
            Text3d text3D = new Text3d(text, plane, height)
            {
                HorizontalAlignment = TextHorizontalAlignment.Center,
                VerticalAlignment = TextVerticalAlignment.Middle,
            };
            return BakeOne(text3D, objectAttributes);
        }
        public Guid Bake(Text3d geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Text3d> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Text3d> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        Guid[] BakeMulti<T>(IEnumerable<T> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            List<Guid> result = new List<Guid>();
            T[] arrayGeos = geos.ToArray();
            ObjectAttributes[] arrayAttr = objectAttributes.ToArray();
            if (arrayAttr.Length == arrayGeos.Length)
            {
                for (int i = 0; i < arrayAttr.Length; i++)
                {
                    Guid id = BakeOne(arrayGeos[i], arrayAttr[i]);
                    if (id != Guid.Empty) result.Add(id);
                }
            }
            return result.ToArray();
        }
        Guid[] BakeMulti<T>(IEnumerable<T> geos)
        {
            List<Guid> result = new List<Guid>();
            foreach (T geo in geos)
            {
                Guid id = BakeOne(geo, null);
                if (id != Guid.Empty) result.Add(id);
            }
            return result.ToArray();
        }
        Guid BakeOne<T>(T geo, ObjectAttributes objectAttributes)
        {
            switch (geo)
            {
                case Point3d pt:
                    if (pt.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddPoint(pt, objectAttributes);
                    break;
                case Point3f ptf:
                    if (ptf.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddPoint(ptf, objectAttributes);
                    break;
                case PointCloud ptCloud:
                    if (ptCloud.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddPointCloud(ptCloud, objectAttributes);
                    break;
                case Line line:
                    if (line.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddLine(line, objectAttributes);
                    break;
                case Box box:
                    if (box.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddBox(box, objectAttributes);
                    break;
                case BoundingBox bbox:
                    if (bbox.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddBox(new Box(bbox), objectAttributes);
                    break;
                case Circle circle:
                    if (circle.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddCircle(circle, objectAttributes);
                    break;
                case Arc arc:
                    if (arc.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddArc(arc, objectAttributes);
                    break;
                case Ellipse ellipse:
                    if (ellipse.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddEllipse(ellipse, objectAttributes);
                    break;
                case Cone cone:
                    if (cone.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddSurface(cone.ToNurbsSurface(), objectAttributes);
                    break;
                case Rectangle3d rectangle:
                    if (rectangle.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddRectangle(rectangle, objectAttributes);
                    break;
                case Polyline polyline:
                    if (polyline.IsValid && polyline.Count > 1)
                        return RhinoDoc.ActiveDoc.Objects.AddPolyline(polyline, objectAttributes);
                    break;
                case Cylinder cylinder:
                    if (cylinder.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddBrep(cylinder.ToBrep(true, true), objectAttributes);
                    break;
                case Plane plane:
                    return BakePlane(plane, objectAttributes);
                case Sphere sphere:
                    if (sphere.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddSphere(sphere, objectAttributes);
                    break;
                case GeometryBase geometry:
                    return BakeGeometry(geometry, objectAttributes);
                case RhinoObject rhinoObject:
                    if (objectAttributes == null)
                        objectAttributes = rhinoObject.Attributes;
                    if (rhinoObject is InstanceObject instanceObject)
                        return RhinoDoc.ActiveDoc.Objects.AddInstanceObject(instanceObject.InstanceDefinition.Index, instanceObject.InstanceXform, objectAttributes);
                    else
                        return RhinoDoc.ActiveDoc.Objects.Add(rhinoObject.Geometry, objectAttributes);
                case Text3d text3D:
                    return RhinoDoc.ActiveDoc.Objects.AddText(text3D, objectAttributes);
            }
            return Guid.Empty;
        }
        Guid BakeGeometry(GeometryBase geometry, ObjectAttributes objectAttributes)
        {
            if (geometry.IsValid)
                return RhinoDoc.ActiveDoc.Objects.Add(geometry, objectAttributes);
            else
            {
                switch (geometry)
                {
                    case Mesh mesh:
                        return RhinoDoc.ActiveDoc.Objects.AddMesh(mesh, objectAttributes, null, false, false);
                    case Brep brep:
                        return RhinoDoc.ActiveDoc.Objects.AddBrep(brep, objectAttributes, null, false, false);
                    default:
                        return RhinoDoc.ActiveDoc.Objects.Add(geometry, objectAttributes);
                }
            }
        }
        Guid BakePlane(Plane plane, ObjectAttributes objectAttributes)
        {
            Point3d pt = RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport.CameraTarget;
            RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport.GetWorldToScreenScale(pt, out double pixelPerUnit);
            double s = 40 / pixelPerUnit;
            Polyline pl = new Polyline(10)
            {
                plane.PointAt(0,0,s),
                plane.Origin,
                plane.PointAt(s,0,0),
                plane.Origin,
                plane.PointAt(0,s,0),
                plane.PointAt(s,s,0),
                plane.PointAt(s,-s,0),
                plane.PointAt(-s,-s,0),
                plane.PointAt(-s,s,0),
                plane.PointAt(0,s,0)
            };
            return RhinoDoc.ActiveDoc.Objects.AddPolyline(pl, objectAttributes);
        }
        #endregion
        #region Print

        public void Print(string text)
        {
            RhinoApp.WriteLine(text);
        }
        public void Print(string content, params object[] args)
        {
            RhinoApp.WriteLine(string.Format(content, args));
        }
        public void Print(object obj)
        {
            if (obj is IEnumerable iEnumerable)
            {
                string name = iEnumerable.GetType().Name;
                name = name.Substring(0, name.Length - 2);

                string content = $""{name}"" + "" { "";
                int count = 0;
                foreach (object obj2 in iEnumerable)
                {
                    if (count == 0)
                    {
                        content += obj2.ToString();
                    }
                    else if (count < 10)
                    {
                        content += "", "" + obj2.ToString();
                    }
                    else if (count == 10)
                    {
                        content += $"", ......"";
                    }
                    count++;
                }
                content += "" } "" + $"" ({count})"";
                RhinoApp.WriteLine(content);
            }
            else if (obj is string ss)
            {
                RhinoApp.WriteLine(ss);
            }
            else RhinoApp.WriteLine($""[{obj.GetType()}] {obj}"");
        }
        #endregion
        #region Loop

        Thread loopThread;
        /// <summary>
        /// 开启循环
        /// </summary>
        public void LoopOn()
        {
            if (!OnLoop)
            {
                Type typeFromHandle = typeof(RhpBaseScripts);
                Type type = GetType();
                if (type.GetMethod(""Loop"", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).DeclaringType != typeFromHandle)
                {
                    OnLoop = true;
                    previewer.LoopOn = true;
                    loopThread = new Thread(StartLoop);
                    loopThread.Start();
                }
            }
        }
        public void LoopOff()
        {
            OnLoop = false;
            Thread.Sleep(300);
            loopThread?.Abort();
        }
        internal bool OnLoop { get; private set; } = true;
        void StartLoop()
        {
            try
            {
                while (OnLoop && previewer.Enabled)
                {
                    Loop();
                }
            }
            catch (Exception ex)
            {
                RhinoApp.WriteLine(""Loop() exit with exception:\n"" + ex.ToString());
            }
        }
        public virtual void Loop()
        {

        }

        /// <summary>
        /// 暂停一段时间
        /// </summary>
        public void Sleep(int milliseconds)
        {
            Thread.Sleep(milliseconds);
        }

        #endregion
    }
}
";
        readonly string forCompile_Previewer =
@"using Rhino;
using Rhino.Display;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.UI;
using System;
using System.Collections.Generic;
using System.Drawing;
namespace RhpCompile
{
    class Previewer : DisplayConduit
    {
        static Previewer _Instance;
        public static Previewer Instance
        {
            get
            {
                if (_Instance == null) _Instance = new Previewer();
                return _Instance;
            }
        }
        readonly MouseClick mouseClick;
        Previewer()
        {
            mouseClick = new MouseClick(this);
        }
        BoundingBox ClippingBox = BoundingBox.Empty;
        public void Clear()
        {
            LoopOn = false;
            previewObjects.Clear();
            ClippingBox = BoundingBox.Empty;
        }
        public void ClosePreview()
        {
            Clear();
            Enabled = false;
            mouseClick.Enabled = false;
            RhinoDoc.ActiveDoc.Views.Redraw();
        }
        public void EnableDraw()
        {
            Enabled = true;
            mouseClick.Enabled = true;
        }
        public static Color DefaultColor = Color.FromArgb(150, 2, 45, 80);
        readonly List<PreviewObject> previewObjects = new List<PreviewObject>();
        public bool IsEmpty => previewObjects.Count == 0 && (!LoopOn);
        public bool LoopOn { get; set; } = false;
        protected override void PostDrawObjects(DrawEventArgs e)
        {
            foreach (PreviewObject previewObject in previewObjects)
            {
                try
                {
                    if (previewObject != null && previewObject.Enable)
                    {
                        previewObject.Draw(e.Display);
                    }
                }
                catch
                {
                }
            }
        }
        const float buttonWidth = 140;
        const float buttonHeight = 35;
        public RectangleF PreviewRec { get; private set; } = RectangleF.Empty;
        static readonly Color fillColor = Color.FromArgb(0, 35, 67);
        static readonly Color edgeColor = Color.FromArgb(5, 60, 99);
        protected override void DrawOverlay(DrawEventArgs e)
        {
            if ((!IsEmpty) && e.Viewport.Id == RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewportID)
            {
                PreviewRec = new RectangleF(e.Viewport.Bounds.Width - (buttonWidth + buttonHeight * 0.2f), (buttonHeight * 0.2f), buttonWidth, buttonHeight);
                PointF PreviewRecCenter = new PointF(PreviewRec.X + PreviewRec.Width / 2, PreviewRec.Y + PreviewRec.Height / 2);
                e.Display.Draw2dText(""Preview Off"", Color.White, new Point2d(PreviewRecCenter.X, PreviewRecCenter.Y), true, 16, ""Arial Black"");
                e.Display.DrawRoundedRectangle(PreviewRecCenter, PreviewRec.Width, PreviewRec.Height, 5, edgeColor, 4, fillColor);
            }
        }
        protected override void CalculateBoundingBox(CalculateBoundingBoxEventArgs e)
        {
            e.IncludeBoundingBox(ClippingBox);
        }
        public void Preview(Vector3d vector3d, Point3d from, Color color)
        {
            if (from.IsValid && vector3d.IsValid && (!vector3d.IsZero))
            {
                PreviewVector previewVector = new PreviewVector(vector3d, from, color);
                previewObjects.Add(previewVector);
                ClippingBox.Union(previewVector.ClippingBox);
            }
        }
        public void Preview(object geo, Color color)
        {
            switch (geo)
            {
                case Point3d pt:
                    if (pt.IsValid)
                    {
                        previewObjects.Add(new PreviewPoint(pt, color));
                    }
                    break;
                case Point3f ptf:
                    if (ptf.IsValid)
                    {
                        previewObjects.Add(new PreviewPoint(new Point3d(ptf), color));
                    }
                    break;
                case PointCloud cloud:
                    if (cloud.IsValid)
                    {
                        previewObjects.Add(new PreviewPointCloud(cloud, color));
                    }
                    break;
                case Line line:
                    if (line.IsValid)
                        previewObjects.Add(new PreviewStructGeos(line, color));
                    break;
                case Box box:
                    if (box.IsValid)
                        previewObjects.Add(new PreviewBox(box, color));
                    break;
                case BoundingBox bbox:
                    if (bbox.IsValid)
                        previewObjects.Add(new PreviewBox(new Box(bbox), color));
                    break;
                case Circle circle:
                    if (circle.IsValid)
                        previewObjects.Add(new PreviewCircle(circle, color));
                    break;
                case Arc arc:
                    if (arc.IsValid)
                        previewObjects.Add(new PreviewArc(arc, color));
                    break;
                case Ellipse ellipse:
                    if (ellipse.IsValid)
                        previewObjects.Add(new PreviewCurve(ellipse.ToNurbsCurve(), color));
                    break;
                case Cone cone:
                    if (cone.IsValid)
                        previewObjects.Add(new PreviewCone(cone, color));
                    break;
                case Rectangle3d rectangle:
                    if (rectangle.IsValid)
                        previewObjects.Add(new DrawPolyline(rectangle.ToPolyline(), color));
                    break;
                case Polyline polyline:
                    if (polyline.IsValid && polyline.Count > 1)
                        previewObjects.Add(new DrawPolyline(polyline, color));
                    break;
                case Cylinder cylinder:
                    if (cylinder.IsValid)
                        previewObjects.Add(new DrawCylinder(cylinder, color));
                    break;
                case Plane plane:
                    if (plane.IsValid)
                        previewObjects.Add(new PreviewPlane(plane, color));
                    break;
                case Sphere sphere:
                    if (sphere.IsValid)
                        previewObjects.Add(new DrawSphere(sphere, color));
                    break;
                case AnnotationBase annotationBase:
                    previewObjects.Add(new PreviewAnnotationBase(annotationBase, color));
                    break;
                case Hatch hatch:
                    previewObjects.Add(new PreviewHatch(hatch, color));
                    break;
                case TextDot textDot:
                    previewObjects.Add(new PreviewTextDot(textDot, color));
                    break;
                case Curve crv:
                    previewObjects.Add(new PreviewCurve(crv, color));
                    break;
                case Text3d text3D:
                    previewObjects.Add(new PreviewText3d(text3D, color));
                    break;
                case GeometryBase geometry:
                    previewObjects.Add(new PreviewGeometryBase(geometry, color));
                    break;
                case RhinoObject rhinoObject:
                    previewObjects.Add(new PreviewRhinoObject(rhinoObject, color));
                    break;
            }
            if (previewObjects.Count > 0)
                ClippingBox.Union(previewObjects[previewObjects.Count - 1].ClippingBox);
        }
    }
    #region PreviewerObject
    abstract class PreviewObject
    {
        public bool Enable { get; private set; } = true;
        public Color DrawColor { get; set; }
        public BoundingBox ClippingBox { get; protected set; }
        public PreviewObject(Color drawColor)
        {
            DrawColor = drawColor;
        }
        public abstract void Draw(DisplayPipeline display);
    }
    class PreviewVector : PreviewObject
    {
        readonly Line line;
        public PreviewVector(Vector3d vec, Point3d pt, Color color) : base(color)
        {
            line = new Line(pt, vec + pt);
            ClippingBox = line.BoundingBox;
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawArrow(line, DrawColor);
        }
    }
    class PreviewGeometryBase : PreviewObject
    {
        readonly Mesh[] previewMesh;
        readonly DisplayMaterial material;
        readonly bool m_DrawMeshVerticesColor = false;
        public PreviewGeometryBase(GeometryBase geo, Color color) : base(color)
        {
            material = new DisplayMaterial(color, 1 - color.A / 255.0);
            switch (geo)
            {
                case Mesh mesh:
                    previewMesh = new Mesh[] { mesh.DuplicateMesh() };
                    m_DrawMeshVerticesColor = mesh.VertexColors.Count > 0;
                    break;
                case Extrusion extrusion:
                    previewMesh = Mesh.CreateFromBrep(extrusion.ToBrep(), MeshingParameters.FastRenderMesh);
                    break;
                case Brep brep:
                    previewMesh = Mesh.CreateFromBrep(brep, MeshingParameters.FastRenderMesh);
                    break;
                case Surface surface:
                    previewMesh = new Mesh[] { Mesh.CreateFromSurface(surface, MeshingParameters.FastRenderMesh) };
                    break;
                default:
                    previewMesh = Array.Empty<Mesh>();
                    break;
            }
            if (previewMesh != null)
            {
                foreach (Mesh mesh in previewMesh)
                {
                    if (mesh.FaceNormals.Count == 0 || mesh.Normals.Count == 0)
                    {
                        mesh.RebuildNormals();
                        mesh.FaceNormals.ComputeFaceNormals();
                    }
                }
            }
            ClippingBox = geo.GetBoundingBox(false);
        }
        public override void Draw(DisplayPipeline display)
        {
            if (m_DrawMeshVerticesColor)
            {
                foreach (Mesh mesh in previewMesh)
                {
                    display.DrawMeshFalseColors(mesh);
                }
            }
            else
            {
                foreach (Mesh mesh in previewMesh)
                {
                    display.DrawMeshShaded(mesh, material);
                }
            }
        }
    }
    class PreviewAnnotationBase : PreviewObject
    {
        readonly AnnotationBase annotationBase;
        public PreviewAnnotationBase(AnnotationBase annotationBase, Color color) : base(color)
        {
            this.annotationBase = annotationBase.Duplicate() as AnnotationBase;
            ClippingBox = annotationBase.GetBoundingBox(false);
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawAnnotation(annotationBase, DrawColor);
        }
    }
    class PreviewRhinoObject : PreviewObject
    {
        readonly RhinoObject rhinoObject;
        public PreviewRhinoObject(RhinoObject rhinoObject, Color color) : base(color)
        {
            this.rhinoObject = rhinoObject;
            ClippingBox = rhinoObject.Geometry.GetBoundingBox(false);
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawObject(rhinoObject);
        }
    }
    class PreviewTextDot : PreviewObject
    {
        readonly TextDot textDot;
        public PreviewTextDot(TextDot text, Color color) : base(color)
        {
            textDot = text.Duplicate() as TextDot;
            ClippingBox = text.GetBoundingBox(false);
        }
        public override void Draw(DisplayPipeline display)
        {
            display.Draw2dText(textDot.Text, DrawColor, textDot.Point, true, textDot.FontHeight, textDot.FontFace);
        }
    }
    class PreviewHatch : PreviewObject
    {
        readonly Hatch geo;
        public PreviewHatch(Hatch geo, Color color) : base(color)
        {
            this.geo = geo.Duplicate() as Hatch;
            ClippingBox = geo.GetBoundingBox(false);
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawHatch(geo, DrawColor, DrawColor);
        }
    }
    class PreviewText3d : PreviewObject
    {
        readonly Text3d text3d;
        public PreviewText3d(Text3d text3d, Color color) : base(color)
        {
            this.text3d = text3d;
            ClippingBox = text3d.BoundingBox;
        }
        public override void Draw(DisplayPipeline display)
        {
            display.Draw3dText(text3d, DrawColor);
        }
    }
    class PreviewCurve : PreviewObject
    {
        readonly Curve geo;
        public PreviewCurve(Curve geo, Color color) : base(color)
        {
            this.geo = geo.DuplicateCurve();
            ClippingBox = geo.GetBoundingBox(false);
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawCurve(geo, DrawColor);
        }
    }
    class DrawPolyline : PreviewObject
    {
        readonly Polyline geo;
        public DrawPolyline(Polyline geo, Color color) : base(color)
        {
            this.geo = geo.Duplicate();
            ClippingBox = geo.BoundingBox;
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawPolyline(geo, DrawColor);
        }
    }
    class PreviewPlane : PreviewObject
    {
        Plane plane;
        public PreviewPlane(Plane plane, Color color) : base(color)
        {
            this.plane = plane;
        }
        public override void Draw(DisplayPipeline display)
        {
            display.Viewport.GetWorldToScreenScale(plane.Origin, out double pixelsPerUnit);
            double scale = 20 / pixelsPerUnit;
            display.DrawLine(plane.Origin, plane.Origin + plane.XAxis * scale, Color.Red);
            display.DrawLine(plane.Origin, plane.Origin + plane.YAxis * scale, Color.Green);
            display.DrawLine(plane.Origin, plane.Origin + plane.ZAxis * scale, Color.Blue);
            scale *= 0.5;
            Hatch hatch = Hatch.Create(new PolylineCurve(new Point3d[] { plane.Origin, plane.PointAt(scale, 0), plane.PointAt(scale, scale), plane.PointAt(0, scale), plane.Origin }), 0, 0, 1, 0.1)[0];
            display.DrawHatch(hatch, DrawColor, DrawColor);
        }
    }
    class PreviewStructGeos : PreviewObject
    {
        Line line;
        public PreviewStructGeos(Line line, Color color) : base(color)
        {
            this.line = line;
            ClippingBox = line.BoundingBox;
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawLine(line, DrawColor);
        }
    }
    class PreviewPoint : PreviewObject
    {
        Point3d pt;
        public PreviewPoint(Point3d pt, Color color) : base(color)
        {
            this.pt = pt;
            ClippingBox = new BoundingBox(pt, pt + new Vector3d(0.1, 0.1, 0.1));
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawPoint(pt, PointStyle.Simple, 3, DrawColor);
        }
    }
    class PreviewPointCloud : PreviewObject
    {
        readonly PointCloud cloud;
        public PreviewPointCloud(PointCloud cloud, Color color) : base(color)
        {
            this.cloud = cloud;
            ClippingBox = cloud.GetBoundingBox(false);
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawPointCloud(cloud, 1, DrawColor);
        }
    }
    class PreviewBox : PreviewObject
    {
        Box box;
        public PreviewBox(Box box, Color color) : base(color)
        {
            this.box = box;
            ClippingBox = box.BoundingBox;
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawBox(box, DrawColor);
        }
    }
    class PreviewCircle : PreviewObject
    {
        Circle circle;
        public PreviewCircle(Circle circle, Color color) : base(color)
        {
            this.circle = circle;
            ClippingBox = circle.BoundingBox;
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawCircle(circle, DrawColor);
        }
    }
    class PreviewArc : PreviewObject
    {
        Arc arc;
        public PreviewArc(Arc arc, Color color) : base(color)
        {
            this.arc = arc;
            ClippingBox = arc.BoundingBox();
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawArc(arc, DrawColor);
        }
    }
    class PreviewCone : PreviewObject
    {
        Cone geo;
        public PreviewCone(Cone geo, Color color) : base(color)
        {
            this.geo = geo;
            ClippingBox = new BoundingBox(geo.ApexPoint, geo.ApexPoint);
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawCone(geo, DrawColor);
        }
    }
    class DrawCylinder : PreviewObject
    {
        Cylinder geo;
        public DrawCylinder(Cylinder geo, Color color) : base(color)
        {
            this.geo = geo;
            ClippingBox = new BoundingBox(geo.Center, geo.Center + geo.BasePlane.ZAxis * geo.TotalHeight);
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawCylinder(geo, DrawColor);
        }
    }
    class DrawSphere : PreviewObject
    {
        Sphere geo;
        public DrawSphere(Sphere geo, Color color) : base(color)
        {
            this.geo = geo;
            ClippingBox = geo.BoundingBox;
        }
        public override void Draw(DisplayPipeline display)
        {
            display.DrawSphere(geo, DrawColor);
        }
    }
    #endregion
    class MouseClick : MouseCallback
    {
        readonly Previewer owner;
        public MouseClick(Previewer owner)
        {
            this.owner = owner;
        }
        bool _mouseDown = false;
        protected override void OnEndMouseUp(MouseCallbackEventArgs e)
        {
            if (_mouseDown && owner.PreviewRec.Contains(e.ViewportPoint))
            {
                _mouseDown = false;
                owner.ClosePreview();
            }
        }
        protected override void OnMouseDown(MouseCallbackEventArgs e)
        {
            if ((!owner.IsEmpty) && owner.PreviewRec.Contains(e.ViewportPoint))
            {
                e.Cancel = true;
                _mouseDown = true;
                RhinoDoc.ActiveDoc.Views.Redraw();
            }
        }
    }
}
";
        readonly string forCompile_AimoStaticUtils =
@"using Rhino.Geometry;

namespace RhpCompile
{
    static class AimoStaticUtils
    {
        public static Brep ToBrep(this Circle circle)
        {
            return Brep.CreateTrimmedPlane(circle.Plane, circle.ToNurbsCurve());
        }
        public static Brep ToBrep(this Rectangle3d rec)
        {
            return Brep.CreateTrimmedPlane(rec.Plane, rec.ToNurbsCurve());
        }
        public static Brep ToBrep(this Curve crv)
        {
            if (crv != null && crv.IsClosed && crv.TryGetPlane(out Plane plane))
            {
                return Brep.CreateTrimmedPlane(plane, crv);
            }
            return null;
        }
        public static Brep ToBrep(this Polyline pl)
        {
            if (pl != null && pl.IsClosed && pl.Count > 2)
            {
                Curve crv = pl.ToNurbsCurve();
                if (crv.TryGetPlane(out Plane plane, 0.001))
                {
                    return Brep.CreateTrimmedPlane(plane, crv);
                }
                else
                {
                    Mesh mesh = Mesh.CreateFromClosedPolyline(pl);
                    return Brep.CreateFromMesh(mesh, true);
                }
            }
            return null;
        }
        public static Brep ToBrep(this Ellipse ellipse)
        {
            return Brep.CreateTrimmedPlane(ellipse.Plane, ellipse.ToNurbsCurve());
        }

    }
}
";
    }
}
